(function(){
/**
 * 
 * 
 */
function getPromiseCallback(cb) {
	cb = typeof cb === "function" ? cb : null;
	var promise, resolve, reject, callback;
	try{promise = new Promise(function(a, b) {resolve = a; reject = b;});} catch(e){}
	if (cb || promise) {
		callback = function (err, data) {
			promise && (err ? reject(err) : resolve(data));
			cb && cb(err && err.data, data && data.data, err || data);
		};
	}
	return {promise: promise, callback: callback};
}
/**
 * 获取一个回调函数缓存
 */
function getCallbackCache() {
	var list = {}, n = 0;
	var save = function save(func) {
		if (typeof func !== 'function') {
			return;
		}
		list[++n] = func;
		return n;
	}
	var get = function get(id) {
		var func = list[id];
		delete list[id];
		return func;
	}
	return {save, get}
}

//添加监听
function addListener(type, func) {
	var cc = this;
	var that = cc._listener;
	while (that.next) {
		that = that.next;
		if (that.type == type && that.func == func) {
			return false;
		}
	}
	that = that.next = {pre: that, type: type, func: func};
	return true;
}
//移除监听
function removeListener(type, func) {
	var cc = this;
	var that = cc._listener;
	while (that = that.next) {
		if (that.type == type && that.func == func) {
			that.pre.next = that.next;
			if(that.next) {
				that.next.pre = that.pre;
			}
			that.type = null;
			that.func = null;
			return true;
		}
	}
	return false;
}
//消息路由
function router(msg, handle, next) {
	if (typeof handle === "function") {
		next = handle;
		handle = undefined;
	}
	if(!isMessage(msg)) {
		if(typeof next === "function") {
			return next(msg, handle);
		}
		return ;
	}
	var cc = this;

	var origin = msg.origin
	var source = msg.source;
	msg = source ? msg.data : msg;
	//数据, 类型, 处理后执行的回调函数Id, 此次要执行的回调函数
	var data = msg.data, type = msg.type, callback = msg.callback, response = cc._getcb(msg.response);
	//外层执行的回调函数
	var cb = function(data, msgtype, notNeedRet, cb) {
		if (typeof msgtype === "function") {
			cb = msgtype;
			notNeedRet = false;
			msgtype = undefined;
		} else if (typeof notNeedRet === "function") {
			cb = notNeedRet;
		}
		if (typeof notNeedRet !== "boolean") {
			if (typeof msgtype === "boolean") {
				notNeedRet = msgtype;
				msgtype = undefined;
			} else {
				notNeedRet = false;
			}
		}
		msgtype = msgtype === null || typeof msgtype === "string" ? msgtype : "";

		var promise = notNeedRet === true ? {} : getPromiseCallback(cb);
		var cbfunc = promise.callback;
		promise = promise.promise;
		//生成消息包
		var msg = {
			data: data,
			type: msgtype,
			callback: cc._savecb(cbfunc)
		};
		if(callback) {
			msg.response = callback;
		}
		//发出消息
		cc._send(msg, source);
		return promise;
	};
	//错误处理
	function error(e) {
		callback && cc._send({data: e instanceof Error ? String(e) : null, type: null, response: callback}, source);
	}
	//监听列表
	var that = cc._listener;
	//监听函数枚举处理
	var next = function() {
		while(that = that.next) {
			if(type !== that.type) {
				continue;
			}
			try {
				return that.func(responseData);
			} catch (e) {
				return error(e);
			}
		}
		return callback && cc._send({data: null, type: '', response:callback}, source);
	};
	var responseData = {
		source: source,
		data: data,
		type: type,
		response: cb,
		next: next
	}
	if (!response) {
		return next();
	}
	try {
		var ret = type === null ? response(responseData) : response(null, responseData);
		try {ret instanceof Promise && ret.catch(error);} catch(e) {}
	} catch(e) {
		error(e);
	}
};
/**
 * 请求消息
 * this 表示源
 */
function send(opt, cb) {
	var data = opt.data, type = opt.type, source = opt.source, cc = this;

	var promise = cb === null || cb === true ? {} : getPromiseCallback(cb);
	var callback = promise.callback;
	promise = promise.promise;

	if(!type || typeof type !== "string") {
		type = "";
	}
	var msg = {
		data: data,
		type: type
	};
	if(callback) {
		msg.callback = cc._savecb(callback);
	}
	cc._getSource(source, function(err, source) {return err ? callback && callback({data: err}) : cc._send(msg, opt.source);});
	return promise;
}

/**
 * 判断是不是用于的messageRouter的事件
 * @param  {MessageEvent}  event 要判断弄得事件
 * @return {Boolean}       是否为该事件
 */
function isMessage(msg) {
	return msg instanceof Object && (typeof msg.type === "string" || msg.type === null);
}

//获取源(函数)
function getSource(w) {
	if (w) {return function(s, cb) {return cb();};}
	var sources = {};
	return function(source, cb) {
		if(source && typeof source === "object") {
			try {source.Window === 1;} catch(e) {return cb(null, source);}
			try {
				if (source instanceof source.Window || window.Worker && source instanceof Worker) {return cb(null, source);}
			} catch(e) {
				return cb(e);
			}
		}
		if(typeof source !== "string") {cb(new Error("The source should be a Window Object, a Worker Object, or a string like URL"));}
		if(sources[source]) {return sources[source](cb);}
		var iframe = document.createElement("iframe");
		//回调函数列表 或 源。如果源未加载，则为回调函数列表；如果源已经加载，则为源
		var s = [cb];
		//加载完成列表, 依次执行回调
		iframe.onload = function(){for(var i = 0; i < s.length; i++) {try{s[i](null, s);}catch(e){}};s = iframe.contentWindow;}
		//设置源
		sources[source] = function(cb) {if(s instanceof Array) {return s.push(cb);} return cb(null, s);}
		//加载
		iframe.src = source;iframe.style.display = "none";document.body.appendChild(iframe);
	}
};

function returnFalse() {return false;}
function returnNext(m, h, n) {return typeof h === "function" && h(m) || typeof n === "function" && n(m, h);}

function init(source, next) {
	var cb = getCallbackCache();
	var cc = {
		_listener: {},
		_savecb: cb.save,
		_getcb: cb.get,
		_getSource: getSource(source),
		_send: function(msg, src) { source ? source.send(msg) : src.postMessage(msg, "*");},
	}
	cc.send = cc.request = send.bind(cc);
	cc.on = cc.addListener = addListener.bind(cc);
	cc.off = cc.removeListener = removeListener.bind(cc);
	cc.router = router.bind(cc);
	var message = function(a, b) {return cc.router(a, b, next);};
	var exit = function() {
		delete cc._listener;
		delete cc._savecb;
		delete cc._getcb;
		cc.off = cc.removeListener = cc.on = cc.addListener = returnFalse;
		cc.send = cc.request = function(opt, cb) {}/////////////////
		cc.router = returnNext;
		source && source.removeListener("message", message);
		source && source.removeListener("exit", exit);
	}
	source && source.on("message", message);
	source && source.on("exit", exit);
	return cc;
}

try {
	window.window.window === window;
	var cc = init()
	if (!window.onmessage) {
		window.onmessage = cc.router;
	}
	if (typeof window.define === "function") {
		define("crosscom", function() {
			return cc;
		})
	} else {
		window.crosscom = cc;
	}
} catch(e) {
	module.exports = function(s, n) {
		if (!s) {
			return null;
		}
		return init(s, n);
	}
}


})();
